﻿// ****************************************************************
// Copyright 2012, Stephan Burguchev
// e-mail: me@sburg.net
// ****************************************************************
// *
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.ServiceModel.Syndication;
using System.Text.RegularExpressions;
using System.Xml;
using ColdLight.Common.Mono.Options;

namespace RssGenerator
{
    internal class Program
    {
        private static string GetIP()
        {
            var wc = new WebClient();
            string strIP = wc.DownloadString("http://checkip.dyndns.org");
            strIP = (new Regex(@"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b")).Match(strIP).Value;
            wc.Dispose();
            return strIP;
        }

        private static int Main(string[] args)
        {
            string ip = GetIP();

            FileStream s = File.OpenRead(@"D:\Documents\svn_ifz_trv\trunk\tmp\Any-0.8.0.50.zip");
            long size = s.Length;
            byte[] hash = SHA1.Create().ComputeHash(s);
            string str = Convert.ToBase64String(hash);

            const string addCommand = "ADD";

            List<string> extra;

            string filename = null;
            string command = null;
            string updatesLocation = null;
            bool verbose = false;
            bool help = false;

            var p = new OptionSet
                {
                    // Definition of global properties
                    /*{
                                "D:", "Predefine a global property with an value.",
                                (m, v) =>
                                    {
                                        if (m == null)
                                            throw new OptionException("Missing macro name for option -D.", "-D");
                                        globalProperties.Add(new Property(m, v));
                                    }
                            },
                            {
                                "d={-->}{=>}", "Alternate global property syntax.",
                                (m, v) => globalProperties.Add(new Property(m, v))
                            },*/
                    // other options
                    { "f|file=", "A RSS file to process.", v => filename = v },
                    {
                        "c|command=", "A command to execute. Currently supported commands are:\r\n\r\n" +
                                      "ADD - add a new patch entry.\r\n",
                        v => command = v
                    },
                    { "updates-loc=", "An updates location.", v => updatesLocation = v },
                    // standard flags
                    { "debug", "Verbose debug messages.", v => verbose = v != null },
                    { "h|help", "Show this message and exit.", v => help = v != null }
                };

            try
            {
                extra = p.Parse(args);

                // displaying help if needed
                if (help)
                {
                    showHelp(p);
                    return 1;
                }

                // adjusting verbosity
                if (verbose)
                {
                    //ColdLight.Log4Net.Logger.SetThresholdForAppender("ConsoleAppender", Level.Debug);
                }

                // Checking required options
                assertNotEmpty("file", filename);
                assertNotEmpty("command", command);
                assertNotEmpty("updates-loc", updatesLocation);

                if (command == addCommand)
                {
                    if (extra.Count > 1)
                    {
                        showHelp(p);
                        return 1;
                    }
                }
                else // if (extra.Count > 0)
                {
                    showHelp(p);
                    return 1;
                }
            }
            catch (OptionException e)
            {
                syntaxError(e.Message);
                return 1;
            }
            catch (FormatException ex)
            {
                syntaxError(ex.Message);
                return 1;
            }

            try
            {
                // Command ADD
                string version = extra[0];
                updatesLocation = updatesLocation.EndsWith("/")
                                      ? updatesLocation
                                      : updatesLocation + "/";

                SyndicationFeed feed;
                using (XmlReader reader = XmlReader.Create(filename))
                {
                    feed = SyndicationFeed.Load(reader);
                }

                if (feed == null)
                {
                    throw new Exception(string.Format("Failed to create a RSS feed from the file '{0}'.", filename));
                }

                foreach (SyndicationItem item in feed.Items)
                {
                    var link = new SyndicationLink(
                        new Uri(updatesLocation + item.AttributeExtensions[new XmlQualifiedName("version")].Replace(".", "-")));
                    link.RelationshipType = "alternate";
                    if (item.Links.Count > 0)
                    {
                        item.Links[0] = link;
                    }
                    else
                    {
                        item.Links.Add(link);
                    }
                }

                var newItem = new SyndicationItem(
                    string.Format("Обновление {0}", version), " ", new Uri(updatesLocation + version.Replace(".", "-")));
                newItem.PublishDate = DateTime.Now;
                newItem.AttributeExtensions.Add(new XmlQualifiedName("version"), version);
                feed.Items = feed.Items.Concat(new[] { newItem }).ToList();

                using (FileStream output = File.Create(filename))
                {
                    using (XmlWriter rssWriter = XmlWriter.Create(
                        output,
                        new XmlWriterSettings
                            {
                                Indent = true,
                                IndentChars = "  "
                            }))
                    {
                        feed.GetRss20Formatter(false).WriteTo(rssWriter);
                    }
                }

                /*SyndicationFeed feed = new SyndicationFeed("Test Feed", "This is a test feed", new Uri("http://Contoso/testfeed"));

                SyndicationItem item = new SyndicationItem("Test Item", "This is the content for Test Item", new Uri("http://Contoso/ItemOne"));

                List<SyndicationItem> items = new List<SyndicationItem>();
                items.Add(item);
                items.Add(item);

                feed.Items = items;
                feed.Copyright = new TextSyndicationContent("Copyright © sburg & keir.live 2011-2012");
                feed.Authors.Add(new SyndicationPerson("skara06@gmail.com", "Stephan Burguchev", "http://skara.dyndns.org"));
                feed.Authors.Add(new SyndicationPerson("keir@ifz.ru", "Kirill Kholodkov", "http://netvisor.ru"));
                item.Authors.Add(new SyndicationPerson("skara06@gmail.com", "Stephan Burguchev", "http://skara.dyndns.org"));
                item.Authors.Add(new SyndicationPerson("keir@ifz.ru", "Kirill Kholodkov", "http://netvisor.ru"));

                item.AttributeExtensions.Add(new XmlQualifiedName("version"), "0.9.1.223");
                item.PublishDate = DateTime.Now;

                var ms = new MemoryStream();
                XmlWriter rssWriter = XmlWriter.Create(ms, new XmlWriterSettings() { Indent = true, IndentChars = "  " });
                Rss20FeedFormatter rssFormatter = new Rss20FeedFormatter(feed);

                rssFormatter.SerializeExtensionsAsAtom = false;

                rssFormatter.WriteTo(rssWriter);
                rssWriter.Close();
                var s = Encoding.UTF8.GetString(ms.ToArray());*/

                Console.WriteLine("Operation successfully complete.");
            }
            catch (Exception ex)
            {
                logErrorEx(string.Format("Unknown error occured while the program execution. {0}", ex.Message), ex);
                return 1;
            }

            return 0;
        }

        private static void assertNotEmpty(string name, string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                throw new OptionException(string.Format("Option '{0}' has not been provided or empty.", name), name);
            }
        }

        private static IPAddress findMatch(IPAddress[] addresses, IPAddress gateway)
        {
            byte[] gatewayBytes = gateway.GetAddressBytes();
            foreach (IPAddress ip in addresses)
            {
                byte[] ipBytes = ip.GetAddressBytes();
                if (ipBytes[0] == gatewayBytes[0]
                    && ipBytes[1] == gatewayBytes[1]
                    && ipBytes[2] == gatewayBytes[2])
                {
                    return ip;
                }
            }
            return null;
        }

        private static string getInternetGateway()
        {
            using (var tracert = new Process())
            {
                ProcessStartInfo startInfo = tracert.StartInfo;
                startInfo.FileName = "tracert.exe";
                startInfo.Arguments = "-h 1 208.77.188.166"; // www.example.com
                startInfo.UseShellExecute = false;
                startInfo.RedirectStandardOutput = true;
                tracert.Start();

                using (StreamReader reader = tracert.StandardOutput)
                {
                    string line = "";
                    for (int i = 0; i < 9; ++i)
                    {
                        line = reader.ReadLine();
                    }
                    line = (line ?? "").Trim();
                    return line.Substring(line.LastIndexOf(' ') + 1);
                }
            }
        }

        private static IPAddress getInternetIPAddress()
        {
            try
            {
                IPAddress[] addresses = Dns.GetHostAddresses(Dns.GetHostName());
                IPAddress gateway = IPAddress.Parse(getInternetGateway());
                return findMatch(addresses, gateway);
            }
            catch (FormatException)
            {
                return null;
            }
        }

        private static void logError(string message, params object[] args)
        {
            Console.Error.WriteLine(message, args);
            Console.Error.WriteLine("OPERATION FAILED!");
        }

        private static void logErrorEx(string message, Exception exception)
        {
            Console.Error.WriteLine(message + Environment.NewLine + exception);
            Console.Error.WriteLine("OPERATION FAILED!");
        }

        private static void showHelp(OptionSet p)
        {
            Console.WriteLine("Automatic updates RSS feed generator.");
            Console.WriteLine("Usage: RssGenerator.exe OPTIONS [optional command arguments]");
            Console.WriteLine();
            Console.WriteLine("Options:");
            p.WriteOptionDescriptions(Console.Out);
            Console.WriteLine();
            Console.WriteLine("Commands arguments:");
            Console.WriteLine(
                "  ADD: `<version>`\r\n" +
                "    <version> - the version of a new patch entry.");
        }

        private static void syntaxError(string message)
        {
            Console.Error.WriteLine("Syntax error: ");
            Console.Error.WriteLine(message);
            Console.Error.WriteLine("Try '--help' option for more information.");
        }
    }
}
